#include "Road.h"
#include "Vehicle.h"
#include "Car.h"
#include "Moto.h"
#include "Bus.h"
#include "Truck.h"
#include "GameManager.h"
#include "VehicleInfo.h"
#include "GamePlayLayer.h"
#include "BigMoto.h"
#include "SmallMoto.h"

#define TREE_SPRITE_SCALE 0.3f
#define X_POSITION_START_NORMAL (-10*METTER_TO_POINT);
#define X_POSITION_START_BUS (-30*METTER_TO_POINT);
#define X_POSITION_END_PLUS 200

Road::Road()
{
}

Road::~Road()
{
	vehicles->release();
	trafficLightSprite->removeFromParent();
	trafficTimeRemainingLabel->removeFromParent();
	trafficLightSprite->release();
	trafficTimeRemainingLabel->release();
}

bool Road::init(CCSize size){
	GameObject::init();
	treeDistance = 200;
	setContentSize(size);
	scheduleUpdateWithPriority(-1);
	isRunning = false;
	busLaneMode = GameManager::getInstance()->busLaneMode;
	CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();

	int numTree = size.width/treeDistance;
	for(int i = 0; i < numTree; i++){

		CCSprite* treeSpriteTop = CCSprite::createWithSpriteFrameName("Tree.png");
		treeSpriteTop->setAnchorPoint(CCPointMake(0.5, 0));
		treeSpriteTop->setPosition(CCPointMake(i*treeDistance, size.height));
		treeSpriteTop->setScale(TREE_SPRITE_SCALE);
		addChild(treeSpriteTop);

		CCSprite* treeSpriteBottom = CCSprite::createWithSpriteFrameName("Tree.png");
		treeSpriteBottom->setAnchorPoint(CCPointMake(0.5, 0));
		treeSpriteBottom->setPosition(CCPointMake(i*treeDistance, 0));
		treeSpriteBottom->setScale(TREE_SPRITE_SCALE);
		treeSpriteBottom->setZOrder(1);
		addChild(treeSpriteBottom);
	}

	int lengthToMark = 50;
	for(int i = 0; i < getContentSize().width; i+= lengthToMark*METTER_TO_POINT){
		CCString* labelString = CCString::createWithFormat("%d m", i*POINT_TO_METTER);
		const char* cLabelString = labelString->getCString();
		CCLabelTTF* label = CCLabelTTF::create(cLabelString, "", 16, CCSizeMake(60, 30), kCCTextAlignmentCenter, kCCVerticalTextAlignmentCenter);
		label->setPosition(ccp(i, getContentSize().height/2));
		addChild(label);
	}

	trafficLightSprite = CCSprite::create();
	trafficLightSprite->retain();
	trafficLightSprite->setPosition(ccp(visibleSize.width - 50, visibleSize.height - 100));
	GameManager::getInstance()->gamePlayLayer->addChild(trafficLightSprite);

	trafficTimeRemainingLabel = CCLabelTTF::create("", "", 16, CCSizeMake(60, 30), kCCTextAlignmentCenter, kCCVerticalTextAlignmentCenter);
	trafficTimeRemainingLabel->retain();
	trafficTimeRemainingLabel->setPosition(ccp(trafficLightSprite->getPositionX(), trafficLightSprite->getPositionY() - 40));
	GameManager::getInstance()->gamePlayLayer->addChild(trafficTimeRemainingLabel);

	vehicles = new CCArray;
	lane3Y = size.height/6;     // bottom most
	lane2Y = size.height/2;
	lane1Y = size.height/6*5;   // top most
    
    lane11Y = size.height - 1*METTER_TO_POINT;
    lane12Y = lane11Y - 1*METTER_TO_POINT;
    lane13Y = lane11Y - 2*METTER_TO_POINT;
    lane14Y = lane11Y - 3*METTER_TO_POINT;
    lane15Y = lane11Y - 4*METTER_TO_POINT;
    lane16Y = lane11Y - 5*METTER_TO_POINT;
    lane17Y = lane11Y - 6*METTER_TO_POINT;
    lane18Y = lane11Y - 7*METTER_TO_POINT;
	
//	greenLightTime = GameManager::getInstance()->greenLightTime;
    greenLightTime = 30;
	redLightTime = GameManager::getInstance()->redLightTime;
	setTrafficLightColor(true);

	return true;
}

void Road::draw(){
	glLineWidth( 3.0f );
	ccDrawRect(ccp(0, 0), ccp(getContentSize().width, getContentSize().height));	// road border

	glLineWidth( 1.0f );
	ccDrawLine(ccp(0, getContentSize().height/3), ccp(getContentSize().width, getContentSize().height/3));		// top seperate line
	ccDrawLine(ccp(0, getContentSize().height/3*2), ccp(getContentSize().width, getContentSize().height/3*2));	// bottom seperate line

	// debug
	CCObject* it;
	CCARRAY_FOREACH(vehicles, it){
//		Vehicle* vehicle = (Vehicle*)it;
		//ccDrawRect(ccp(vehicle->getSafeRectBeside().getMinX(), vehicle->getSafeRectBeside().getMinY()), ccp(vehicle->getSafeRectBeside().getMaxX(), vehicle->getSafeRectBeside().getMaxY()));
		/*ccDrawRect(ccp(vehicle->getSafeRect().getMinX(), vehicle->getSafeRect().getMinY()), ccp(vehicle->getSafeRect().getMaxX(), vehicle->getSafeRect().getMaxY()));
		ccDrawRect(ccp(vehicle->getSafeRect().getMinX(), vehicle->getSafeRect().getMinY()), ccp(vehicle->getSafeRect().getMaxX(), vehicle->getSafeRect().getMaxY()));*/
		/*ccDrawRect(ccp(vehicle->getLeftSafeRectNextLane().getMinX(), vehicle->getLeftSafeRectNextLane().getMinY()), ccp(vehicle->getLeftSafeRectNextLane().getMaxX(), vehicle->getLeftSafeRectNextLane().getMaxY()));
		ccDrawRect(ccp(vehicle->getRightSafeRectNextLane().getMinX(), vehicle->getRightSafeRectNextLane().getMinY()), ccp(vehicle->getRightSafeRectNextLane().getMaxX(), vehicle->getRightSafeRectNextLane().getMaxY()));*/
		/*ccDrawRect(ccp(vehicle->getLeftSafeRectBeside().getMinX(), vehicle->getLeftSafeRectBeside().getMinY()), ccp(vehicle->getLeftSafeRectBeside().getMaxX(), vehicle->getLeftSafeRectBeside().getMaxY()));
		ccDrawRect(ccp(vehicle->getRightSafeRectBeside().getMinX(), vehicle->getRightSafeRectBeside().getMinY()), ccp(vehicle->getRightSafeRectBeside().getMaxX(), vehicle->getRightSafeRectBeside().getMaxY()));*/
		//ccDrawRect(ccp(vehicle->boundingBox().getMinX(), vehicle->boundingBox().getMinY()), ccp(vehicle->boundingBox().getMaxX(), vehicle->boundingBox().getMaxY()));
	}
}

void Road::update(float delta){

	if(delta > TIME_NOT_UPDATE)
		return;

	if(isRunning){
		oneSecondTimer->update(delta);

		checkToRemoveVehicle();

		// update position for vehicles
		CCObject* it;
		CCARRAY_FOREACH(vehicles, it){
			Vehicle* vehicle = (Vehicle*)it;
			vehicle->updatePosition(delta);
		}
	}
}

void Road::checkToRemoveVehicle(){
	CCObject* it;

	CCARRAY_FOREACH(vehicles, it){
		Vehicle* vehicle = (Vehicle*)it;
		if(vehicle->getPosition().x > getContentSize().width){
			vehicle->removeFromParent();
			vehicles->removeObject(vehicle);

			VehicleInfo* vehicleInfo = (VehicleInfo*)GameManager::getInstance()->vehicleInfoDictionary->objectForKey(vehicle->getVehicleId());
			if(vehicleInfo)
				vehicleInfo->updateInfo(vehicle);
		}
	}
}

void Road::start(){

	oneSecondTimer = new CCTimer;
	oneSecondTimer->initWithTarget(this, schedule_selector(Road::oneSecondTick), 1, 0, 0);

	isRunning = true;
}

void Road::oneSecondTick(float t){
	trafficLightTimeRemaining--;

	if(trafficLightTimeRemaining == 0)
		setTrafficLightColor(!isGreenLightOn);

	// set label time remaining
	char timeString[4];
	sprintf(timeString, "%d", trafficLightTimeRemaining);
	trafficTimeRemainingLabel->setString(timeString);
    
    // add vehicle
    GameManager* gameManager = GameManager::getInstance();
    gameManager->increaseGameTime();
    
    CCArray* currentVehicleData = GameManager::getInstance()->inputData->getVehicleDataArrayAtTime(gameManager->getGameTime());
    CCObject* it = 0;
    CCARRAY_FOREACH(currentVehicleData, it) {
        VehicleData* vehicleData = (VehicleData*)it;
        addVehicle(vehicleData);
    }
}

void Road::addVehicle(VehicleData* vehicleData) {
    Vehicle* vehicle = 0;
    switch(vehicleData->vehicleType) {
        case ID_BUS:
        {
            vehicle = new Bus();
            vehicle->autorelease();
            vehicle->init();
            break;
        }
            
        case ID_CAR:
        {
            vehicle = new Car();
            vehicle->autorelease();
            vehicle->init();
            break;
        }
            
        case ID_TRUCK:
        {
            vehicle = new Truck();
            vehicle->autorelease();
            vehicle->init();
            break;
        }
            
        case ID_SMALL_MOTO:
        {
            vehicle = new SmallMoto();
            vehicle->autorelease();
            vehicle->init();
            break;
        }
            
        case ID_BIG_MOTO:
        {
            vehicle = new BigMoto();
            vehicle->autorelease();
            vehicle->init();
            break;
        }
    }
    // start v, start lane
    vehicle->readInfo(vehicleData);
    addVehicle(vehicle, vehicleData->startLane);
    vehicle->speedUp();
}

void Road::addVehicle(Vehicle* vehicle, int laneIndex){
    
    vehicle->setRoad(this);

    float xPosition = 0;
    
    switch (laneIndex)
    {
        case 1:
            vehicle->setPosition(ccp(xPosition, lane1Y));
            break;
            
        case 2:
            vehicle->setPosition(ccp(xPosition, lane2Y));
            break;
            
        case 3:
            vehicle->setPosition(ccp(xPosition, lane3Y));
            break;
        case 11:
            vehicle->setPosition(ccp(xPosition, lane11Y));
            break;
        case 12:
            vehicle->setPosition(ccp(xPosition, lane12Y));
            break;
        case 13:
            vehicle->setPosition(ccp(xPosition, lane13Y));
            break;
        case 14:
            vehicle->setPosition(ccp(xPosition, lane14Y));
            break;
        case 15:
            vehicle->setPosition(ccp(xPosition, lane15Y));
            break;
        case 16:
            vehicle->setPosition(ccp(xPosition, lane16Y));
            break;
        case 17:
            vehicle->setPosition(ccp(xPosition, lane17Y));
            break;
        case 18:
            vehicle->setPosition(ccp(xPosition, lane18Y));
            break;
    }
    
    CCObject* it;
    bool isStartable = true;
    CCARRAY_FOREACH(vehicles, it){
        Vehicle* vehicleElement = (Vehicle*)it;
        if(vehicleElement->boundingBox().intersectsRect(vehicle->boundingBox())){
            isStartable = false;
            break;
        }
    }
    
    if(isStartable){
        addChild(vehicle);
        vehicles->addObject(vehicle);
        
        // add to vehicle info
        GameManager::getInstance()->vehicleInfoDictionary->setObject(VehicleInfo::create(vehicle), vehicle->getVehicleId());
    }
}

void Road::setTrafficLightColor(bool isGreen){
	isGreenLightOn = isGreen;

	if(isGreen){
		trafficLightTimeRemaining = greenLightTime;
		trafficLightSprite->setDisplayFrame(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("GreenLight.png"));
	}
	else {
		trafficLightTimeRemaining = redLightTime;
		trafficLightSprite->setDisplayFrame(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("RedLight.png"));
	}

	// set label time remaining
	char timeString[4];
	sprintf(timeString, "%d", trafficLightTimeRemaining);
	trafficTimeRemainingLabel->setString(timeString);
}

CCArray* Road::getVehicles(){
	return vehicles;
}

float Road::getlane3Y(){
	return lane3Y;
}
float Road::getLane1Y(){
	return lane1Y;
}
float Road::getLane2Y(){
	return lane2Y;
}

float Road::getRoadWidth(){
	return getContentSize().height;
}
float Road::getLaneWidth(){
	return getContentSize().height/3;
}

bool Road::getIsGreenLightOn(){
	return isGreenLightOn;
}

bool Road::isAllowTurnToBusLane(int vehicleType){
	switch (busLaneMode)
	{
	case BLM_ALL:
		return true;
		break;
	case BLM_BUS:
		if(vehicleType == ID_BUS)
			return true;
		break;
	case BLM_BUS_MOTOR:
		if(vehicleType == ID_BUS || vehicleType == ID_SMALL_MOTO)
			return true;
		break;
	}
	return false;
}

bool Road::checkVehicleCanTurnBusLaneMode(CCRect safeRect, int vehicleType){
	// if safe rect of vehicle in bus lane && not allow turn to bus lane, return false. Else, return true;
	if(safeRect.getMaxY() > getContentSize().height/3*2 && isAllowTurnToBusLane(vehicleType) == false){
		return false;
	}
	return true;
}

int Road::getWhichLane(Vehicle* vehicle){
	if(vehicle->getPositionY() > getContentSize().height*2/3)
		return 1;
	else if(vehicle->getPositionY() > getContentSize().height/3)
		return 2;
	else return 3;
}

int Road::getWhichLane(CCRect rect){
	float yCenter = rect.getMidY();
	if(yCenter > getContentSize().height*2/3)
		return 1;
	else if(yCenter > getContentSize().height/3)
		return 2;
	else return 3;
}

int Road::rectEntireInLane(CCRect rect){
	float centerLine1 = getContentSize().height*2/3;
	float centerLine2 = getContentSize().height/3;
	if(rect.getMaxY() < getContentSize().height && rect.getMinY() > centerLine1)
		return 1;
	else if(rect.getMaxY() < centerLine1 && rect.getMinY() > centerLine2)
		return 2;
	else if(rect.getMaxY() < centerLine2 && rect.getMinY() > 0)
		return 3;
	else return -1;
}

int Road::getBusLaneMode(){
	return busLaneMode;
}